home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d895.lha / MakeDMake / source / MakeDMake.c < prev   
C/C++ Source or Header  |  1993-07-04  |  14KB  |  549 lines

  1. /*
  2.  *      NAME:           MakeDMake v0.22
  3.  *
  4.  *      PURPOSE:        Automatically construct a makefile for DICE's DMake
  5.  *
  6.  *        PROGRAMMER:        Er... well...
  7.  *                        the idea, portability, elegant calls-by-reference &
  8.  *                        70 percent of the code -- Tim McGrath
  9.  *
  10.  *                        quick'n'dirty globals -- Piotr Obminski
  11.  *
  12.  *
  13.  *      LAST CHANGED:   04 July 1993
  14.  *
  15.  *      COMPILED:       with (registered) DICE (but guess HOW??)
  16.  *
  17.  */
  18.  
  19. #include <stdio.h>
  20.  
  21. #define LINEMAX            80        /* length of line in created DMakeFile */
  22. #define CC_NAME         "dcc"
  23.  
  24. /*
  25.  * default name for executable (only if if given two or more C files).
  26.  * NO '.' (like in 'a.out') please! This is still no UNIX!
  27.  */
  28. #define MAIN_NAME       "main"
  29.  
  30. /*
  31.  * default name for the executable
  32.  */
  33. #define OUTFILE_NAME    "DMakeFile"
  34.  
  35. /*
  36.  * zero if we want call outfile 'DMakeFile' instead of the individualized
  37.  * (unique) name in the form '<executable>.make'
  38.  */
  39. #define UNIQUE_OUTNAME    0
  40.  
  41. /*
  42.  * ANSI sequences, #define them here as '""' (no single quotes)
  43.  * if you hate 'em!
  44.  */
  45. #define    ANSI_BOLD    "›1m"
  46. #define    ANSI_WHITE    "›2m"                /* virtual white */
  47. #define ANSI_NORMAL    "›0m"
  48.  
  49. char main_name[ 80 ] = MAIN_NAME;
  50.  
  51. /*
  52.  * default OPT1 & OPT2 strings -- change if you want hardwired options
  53.  */
  54. #define O2X_OPT         NULL            /* 'object to executable' options */
  55. #define C2O_OPT         NULL            /* 'C to object' options */
  56.  
  57. /*
  58.  * Something like that? Got no "Interface Style Guide" or what's it called...
  59.  */
  60. const char VersionString[] = "$VER: MakeDMake 0.22 (04.07.93) by Piotr Obminski";
  61.  
  62.  
  63. char linking_opts[ 80 ]        = O2X_OPT;
  64. char compi_opts[ 80 ]        = O2X_OPT;
  65.  
  66. FILE *OutFile;
  67.  
  68. void main(), depend_file(), output_objects(), start_line(), continue_line(),
  69.     get_dependents(), move_name(), scan_file();
  70.  
  71.  
  72.     void
  73. main( argc, argv )
  74.     char    **argv;
  75.     int     argc;
  76. {
  77.     int dependent_count;
  78.     char **dependents;
  79.     char outfile_name[ 40 ] = OUTFILE_NAME;
  80.     char temp[ 80 ] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  81.     int good_file_count = 0;
  82.     int i;
  83.     char *p;
  84.  
  85.     /*
  86.      * no input or '?', 'h', 'H' or something beginning with '-', so
  87.      * he needs help!
  88.      */
  89.     if ( argc == 1 || ( *argv[ 1 ] == '?' ) || ( *argv[ 1 ] == '-' ) ||
  90.             ( ( *argv[ 1 ] == 'h' ) && ( *( argv[ 1 ] + 1 ) == '\0' ) )    ||
  91.             ( ( *argv[ 1 ] == 'H' ) && ( *( argv[ 1 ] + 1 ) == '\0' ) ) ) {
  92.  
  93.         puts( "------------------------------------------------------------\n"
  94.                 ANSI_BOLD "MakeDMake v0.22" ANSI_NORMAL ANSI_WHITE
  95.                 "  PD Utility for creating" ANSI_NORMAL ANSI_BOLD
  96.                 " DMakeFile" ANSI_NORMAL "'s\n"
  97.                 "------------------------------------------------------------\n"
  98.                 ANSI_WHITE "USAGE:  " ANSI_NORMAL "Give me names of your "
  99.                 ANSI_BOLD "source files " ANSI_NORMAL
  100.                 "and then we'll\n"
  101.                 "        get interactive.  If I'm successful, the resulting\n"
  102.                 "        " ANSI_BOLD "DMakeFile" ANSI_NORMAL
  103.                 " will be in the current directory.\n"
  104.                 "        Now that you know -- "
  105.                 ANSI_BOLD "START AGAIN" ANSI_WHITE " !\n" ANSI_NORMAL
  106.                 "------------------------------------------------------------" );
  107.  
  108.         exit( 1 );
  109.     }
  110.  
  111.     /*
  112.      * if we got only one command-line argument (from shell!), and it
  113.      * ends in '.c', we start by cutting off this '.c', then we look...
  114.      */
  115.     if ( argc == 2 ) {
  116.         strcpy( temp, argv[ 1 ] );
  117.         if ( ( p = (char *)strstr( temp, ".c" ) ) &&
  118.                                             ( *( p + 2 ) == '\0' ) ) {
  119.             *p = '\0';
  120.             strcpy( main_name, temp );
  121.         }
  122.         else {
  123.             puts( ANSI_BOLD "This stuff you gave me ain't no C code!. "
  124.                     ANSI_NORMAL ANSI_WHITE "Aborting!" ANSI_NORMAL );
  125.             exit( 1 );
  126.         }
  127.     }
  128.  
  129.     /*
  130.      *    get executables name from the user
  131.      */
  132.     printf( ANSI_WHITE "NAME" ANSI_NORMAL " for the " ANSI_WHITE
  133.             "EXECUTABLE" ANSI_NORMAL " ("
  134.             ANSI_BOLD "<RETURN>" ANSI_NORMAL " for "
  135.             ANSI_WHITE "%s" ANSI_NORMAL "):  ", main_name );
  136.  
  137.     gets( temp );
  138.  
  139.     p = temp;
  140.     if ( *p == ' ' || *p == 0x9 ) {
  141.         while ( *p == ' ' || *p == 0x9 )
  142.             p++;
  143.     }
  144.     if ( *p ) {
  145.         strcpy( main_name, p );
  146.  
  147. #if UNIQUE_OUTNAME
  148.            /*
  149.          * change name of the generated MakeFile to <executable>.make
  150.           */
  151.          strcpy( outfile_name, temp );
  152.          strcat( outfile_name, ".make" );
  153. #endif
  154.  
  155.     }
  156.  
  157.     /*
  158.      *    get compilation options from the user
  159.      */
  160.     printf( ANSI_WHITE "OPTIONS" ANSI_NORMAL " for "
  161.             ANSI_WHITE "COMPILATION" ANSI_NORMAL ":  " );
  162.  
  163.     gets( temp );
  164.  
  165.     p = temp;
  166.     if ( *p == ' ' || *p == 0x9 ) {
  167.         while ( *p == ' ' || *p == 0x9 )
  168.             p++;
  169.     }
  170.     strcpy( compi_opts, p );
  171.  
  172.     /*
  173.      *    get linking options from the user
  174.      */
  175.     printf( ANSI_WHITE "OPTIONS" ANSI_NORMAL " for "
  176.             ANSI_WHITE "LINKING" ANSI_NORMAL ":      " );
  177.  
  178.     gets( temp );
  179.  
  180.     p = temp;
  181.     if ( *p == ' ' || *p == 0x9 ) {
  182.         while ( *p == ' ' || *p == 0x9 )
  183.             p++;
  184.     }
  185.     strcpy( linking_opts, p );
  186.  
  187.     printf( "------------------------------------------------------------\n" );
  188.  
  189.     if ( ( OutFile = fopen( outfile_name, "w" ) ) == 0L ) {
  190.         printf( ANSI_BOLD "CAN'T CREATE " ANSI_NORMAL ANSI_WHITE
  191.                     "%s" ANSI_NORMAL ANSI_BOLD " !\n\07" ANSI_NORMAL,
  192.                     outfile_name );
  193.         exit( 1 );
  194.     }
  195.  
  196.     fputs( "# DMakeFile generated by MakeDMake v0.22\n\n", OutFile );
  197.     fprintf( OutFile, "OPT1 = %s\nOPT2 = %s\n\n", linking_opts, compi_opts );
  198.  
  199.     depend_file( argc, argv, main_name, "  ", ".o" );
  200.  
  201.     for ( i = 1; i < argc; i++ ) {
  202.         /* we don't want MakeDMake to make a fool of himself by
  203.          * trying to compile various ReadMe's and Trashcan.icon!
  204.          * So we are skipping such stuff! However it's not always totally
  205.          * successful, so far...
  206.          */
  207.         register char *p;
  208.         if ( ( p = (char *)strstr( argv[ i ], ".c" ) ) &&
  209.                                             ( *( p + 2 ) == '\0' ) ) {
  210.             get_dependents( argv[ i ], &dependents, &dependent_count );
  211.             depend_file( dependent_count, dependents, argv[ i ], ".o", "" );
  212.             free_space( dependents, dependent_count );
  213.             good_file_count++;
  214.         }
  215.         else {
  216.             printf( "%s", argv[ i ] );
  217.             if ( strlen( argv[ i ] ) < 16 )
  218.                 putchar( '\t' );
  219.             if ( strlen( argv[ i ] ) < 8 )
  220.                 putchar( '\t' );
  221.  
  222.             /*
  223.              * the 'bad' input-files are NOT TOTALLY ignored, but it's
  224.              * only cosmetics I thing
  225.              */
  226.             puts( "\t" ANSI_NORMAL ANSI_WHITE "<" ANSI_NORMAL ANSI_BOLD
  227.                     "ignored" ANSI_NORMAL ANSI_WHITE ">" ANSI_NORMAL );
  228.         }
  229.     }
  230.  
  231.     fclose( OutFile );
  232.     if ( good_file_count == 0 ) {
  233.         puts( ANSI_WHITE "Not even one good C file!" ANSI_NORMAL ANSI_BOLD
  234.                 " Who" ANSI_NORMAL "(m) " ANSI_BOLD
  235.                 "do you think you're kidding?" ANSI_NORMAL );
  236.         exit( 1 );
  237.     }
  238.     exit( 0 );
  239. }
  240.  
  241.  
  242.     int
  243. free_space( dp, dc )
  244. /*
  245.  * Purpose: free up list of file names
  246.  * Inputs:  dp - points to list of pointers to strings
  247.  *          dc - number of pointers in the list
  248.  */
  249.     char    **dp;
  250.     int     dc;
  251. {
  252.     while ( dc > 0 ) {
  253.         free( *dp++ );
  254.         dc--;
  255.     }
  256.     /* free( dp ); <--- bad, bad boy! */
  257. }
  258.  
  259.  
  260.     char *
  261. file_exten( pgm_name, xtension, bufout )
  262. /*
  263.  * Purpose: append new extension onto file name
  264.  * Inputs:  pgm_name - pointer to name of file
  265.  *          xtension - pointer to new file name extension (2 chars only)
  266.  * Outputs: bufout - points to area for new file name
  267.  * Returns: bufout
  268.  */
  269.      char *pgm_name, *xtension, *bufout;
  270. {
  271.     int i = 0;
  272.  
  273.     while ( *pgm_name ) {
  274.         bufout[ i++ ] = *pgm_name;
  275.         if ( *pgm_name++ == '.' && xtension[ 0 ] != '\0' ) {
  276.             bufout[ i++ ] = xtension[ 1 ];
  277.             break;
  278.         }
  279.     }
  280.     bufout[ i ] = '\0';  return( bufout );
  281. }
  282.  
  283.  
  284.     void
  285. depend_file( ct, flist, pgm_name, pgmx, filex )
  286. /*
  287.  * Purpose: print file name and list of dependents
  288.  * Inputs:  ct - number of dependents in the list
  289.  *          flist - pointer to a list of pointers to dependent names
  290.  *          pgm_name - name of file whose dependents are being printed
  291.  *          pgmx - extension for pgm_name file (or "" if none)
  292.  *          filex - extension for dependent file names (or "" if none)
  293.  */
  294.     char **flist, *pgm_name, *pgmx, *filex;
  295.     int ct;
  296. {
  297.     int i;
  298.     char buf[ LINEMAX ], add_name[ LINEMAX ], pname[ LINEMAX ];
  299.     char bare_name[ LINEMAX ];
  300.  
  301.     {
  302.         register short i = 0;
  303.  
  304.         do {
  305.             bare_name[ i ] = pgm_name[ i ];
  306.         } while ( pgm_name[ i ] && ( pgm_name[ i++ ] != '.' ) );
  307.  
  308.         bare_name[ --i ] = '\0';
  309.     }
  310.  
  311.     start_line( file_exten( pgm_name, pgmx, pname ), buf );
  312.  
  313.     if ( strcmp( pgm_name, main_name ) )
  314.         strcat( strcat( buf, " " ), pgm_name );
  315.  
  316.     for ( i = 1; i < ct; i++ ) {
  317.  
  318.         file_exten( flist[ i ], filex, add_name );
  319.  
  320.         if ( columns( buf ) + strlen( add_name ) + 1 >= LINEMAX - 1 ) {
  321.             fputs( buf, OutFile ); fputs( "\\\n", OutFile );
  322.             continue_line( file_exten( NULL, NULL, pname ), buf );
  323.         }
  324.         strcat( strcat( buf, " " ), add_name );
  325.     }
  326.     fputs( buf, OutFile ); fputc( '\n', OutFile );
  327.  
  328.     if ( strcmp( pgm_name, main_name ) ) {
  329.         fprintf( OutFile,"\t%s $(OPT2) -c %s.o %s.c\n\n",
  330.                                         CC_NAME, bare_name, bare_name );
  331.     }
  332.     else {
  333.         fprintf( OutFile, "\t%s $(OPT1) -o %s ", CC_NAME, main_name );
  334.         output_objects( flist, ct );
  335.         fputs( "\n\n", OutFile );
  336.     }
  337. }
  338.  
  339.  
  340.     void
  341. output_objects( files, count )
  342.     char **files;
  343.     int count;
  344. {
  345.     unsigned short i, col, len;
  346.     char arr[ 40 ], *brk1, *brk2;
  347.     register char *p;
  348.  
  349.     col = 32;       /* more or less initial column */
  350.  
  351.     for ( i = 1; i < count; i++ ) {
  352.         /* see if file has legal name ending in '.c'
  353.          */
  354.         if ( ( p = (char *)strstr( files[ i ], ".c" ) ) &&
  355.                                             ( *( p + 2 ) == '\0' ) ) {
  356.  
  357.             strcpy( arr, files[ i ] );
  358.  
  359.             len = strlen( arr );
  360.             col += len;
  361.  
  362.             if ( col >= LINEMAX - 2 ) {
  363.                 brk1 = "\\\n\t\t\t";
  364.                 brk2 = "";
  365.                 col = 32 + len + 1;
  366.             }
  367.             else {
  368.                 brk1 = " ";
  369.                 brk2 = "";
  370.                }
  371.  
  372.             p = (char *)strchr( arr, '.' );
  373.             *++p = 'o';
  374.  
  375.             fprintf( OutFile, "%s%s%s", brk1, arr, brk2 );
  376.         }
  377.     }
  378. }
  379.  
  380.  
  381.     void
  382. start_line( with_name, buf )
  383. /*
  384.  * Purpose: give each line a standard indentation
  385.  * Inputs:  with_name - name of root file on each line
  386.  *          buf - place to put indented line
  387.  */
  388.     char *with_name, *buf;
  389. {
  390.     strcpy( buf, with_name ); strcat( buf, "\t" );
  391.  
  392.     if ( columns( buf ) < 16 )
  393.         strcat( buf, "\t" );
  394.  
  395.     if ( columns( buf ) < 24 )
  396.         strcat( buf, "\t" );
  397.  
  398.     strcat( buf, ":" );
  399. }
  400.  
  401.  
  402.     void
  403. continue_line( with_name, buf )
  404. /*
  405.  * Purpose: let the line continue after '\' and '\n'
  406.  * Inputs:  with_name - name of root file on each line
  407.  *          buf - place to put indented line
  408.  */
  409.     char *with_name, *buf;
  410. {
  411.     strcpy( buf, with_name );
  412.     strcat( buf, "\t " );
  413.  
  414.     if ( columns( buf ) < 16 )
  415.         strcat( buf, "\t " );
  416.  
  417.     if ( columns( buf ) < 24 )
  418.         strcat( buf, "\t " );
  419. }
  420.  
  421.  
  422.     int
  423. columns( s )
  424. /*
  425.  * Purpose: count the number of columns a line spans
  426.  * Inputs:  s - the characters in a line
  427.  * Returns: the number of columns ( including tab expansion )
  428.  */
  429.     char *s;
  430. {
  431.     int col = 0;
  432.  
  433.     while ( *s ) {
  434.         if ( *s++ == '\t' )
  435.             while ( ++col & 7 )
  436.                 ;
  437.         else ++col;
  438.     }
  439.     return( col );
  440. }
  441.  
  442.  
  443.     void
  444. get_dependents( fn, depv, depc )
  445. /*
  446.  * Purpose: return a list of files depending on a C source file
  447.  * Inputs:  fn - name of the c source file
  448.  * Outputs: depv - list of dependents (an array of pointers to filenames)
  449.  *          depc - number of dependents
  450.  */
  451.      char *fn, ***depv;
  452.      int *depc;
  453. {
  454.     char **lst;
  455.     int i;
  456.  
  457.     lst = (char **)malloc( 1024 * sizeof( char * ) );
  458.     move_name( &lst[ 0 ], fn );
  459.     fputs( fn, stdout ); fputc( '\n', stdout ); i = 0;
  460.  
  461.     scan_file( lst, &i, fn ); *depv = lst; *depc = i + 1;
  462. }
  463.  
  464.  
  465.     void
  466. move_name( p, s )
  467. /*
  468.  * Purpose: Allocate space for a new filename and copy it
  469.  * Inputs:  p - location for new pointer to filename
  470.  *          s - pointer to file name
  471.  */
  472.      char **p, *s;
  473. {
  474.     *p = (char *)malloc( strlen( s ) + 1 );
  475.     strcpy( *p, s );
  476. }
  477.  
  478.  
  479.     void
  480. scan_file( file_name_list, last_list_used, fn )
  481. /*
  482.  * Purpose: search a C source file file #includes, and search the #includes
  483.  *          for nested #includes
  484.  * Inputs:  fn - name of file to scan
  485.  * Outputs: file_name_list - list of included files
  486.  *          last_list_used - last used filename position in file_name_list
  487.  */
  488.     char **file_name_list, *fn;
  489.     int *last_list_used;
  490. {
  491.     FILE *fp;
  492.     char buf[ 1024 ], ifn[ LINEMAX ];
  493.     int j,k;
  494.  
  495.     fp = fopen( fn, "r" );
  496.  
  497.     if ( ! fp ) {
  498.         fprintf( stdout, ANSI_BOLD "\tcouldn't open file "
  499.                     ANSI_NORMAL ANSI_WHITE "%s\n" ANSI_NORMAL, fn );
  500.         return;
  501.     }
  502.  
  503.     while ( fgets( buf, 1024, fp ) ) {
  504.         if ( strncmp( buf, "#include", 8 ) == 0 ) {
  505.             j = 8;
  506.             while ( buf[ j ] == ' ' || buf[ j ] == '\t' )
  507.                 j++;
  508.             if ( buf[ j++ ] != '"' )
  509.                 continue;
  510.             k = 0;
  511.             while ( buf[ j ] ) {
  512.                 if ( buf[ j ] == '"' || buf[ j ] == '\n' )
  513.                     break;
  514.                 else
  515.                     ifn[ k++ ] = buf[ j++ ];
  516.             }
  517.             ifn[ k ] = '\0';
  518.             if ( add_name( file_name_list, last_list_used, ifn ) )
  519.                 scan_file( file_name_list, last_list_used, ifn );
  520.         }
  521.     }
  522.     fclose( fp );
  523. }
  524.  
  525.  
  526.     int
  527. add_name( file_name_list, last_list_used, fn )
  528. /*
  529.  * Purpose: Add a file name to the list if it's not there already
  530.  * Inputs:  file_name_list - pointer to array of pointers to file names
  531.  *          last_list_used - last element in array with a filename
  532.  *          fn - name of file
  533.  * Returns: 1 if file name added, 0 otherwise
  534.  */
  535.     char **file_name_list, *fn;
  536.     int *last_list_used;
  537. {
  538.     int i;
  539.  
  540.     for ( i = 0; i <= *last_list_used; i++ )
  541.         if ( ! strcmp( file_name_list[ i ], fn ) )
  542.             return( 0 );
  543.  
  544.     *last_list_used += 1;
  545.     move_name( &file_name_list[ *last_list_used ], fn );
  546.     return( 1 );
  547. }
  548.  
  549.